package com.lk.sys.common.aspect;

import com.lk.sys.common.annotation.RequiredLog;
import com.lk.sys.entity.SysLog;
import com.lk.sys.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

@Slf4j
@Aspect
@Component
public class SysLogAspect {
    /*
     * @PoingCut 注解一般用于描述方法，在方法上定义切入点
     * @author Lukang
     * @date 2022/1/7 下午11:49
     */
    @Pointcut("bean(sysUserServiceImpl)")
    public void pointCut(){}//方法内部不需要写任何内容

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint JP) throws Throwable {
        try {
            //1. 记录方法执行时开始的时间
            long start = System.currentTimeMillis();
            log.info("开始时间：{}", start);
            //2. 调用目标方法
            Object result = JP.proceed();
            //3. 记录方法结束后的时间
            long end = System.currentTimeMillis();
            log.info("结束时间：{}", end);
            log.info("method execute time: {}", (end-start));
            saveLog(JP, (end-start));
            return result;
        }catch (Throwable e){
            log.error("error message is : {}", e.getMessage());
            throw e;
        }

    }

    @Autowired
    private SysLogService sysLogService;
    private void saveLog(ProceedingJoinPoint JP, Long time) throws NoSuchMethodException {
        //1.获取用户行为
        //1.1获取目标方法的全名称
        //获取目标方法类的类型
        Class<?> targetCls = JP.getTarget().getClass();
        //获取目标方法类的名称
        String targetClsName = targetCls.getName();
        //获取目标签名方法
        MethodSignature ms = (MethodSignature) JP.getSignature();
        //获取目标方法的名称
        String methodName = ms.getName();
        //获取目标方法的全名称
        String method = targetClsName + methodName;
        //1.2 获取RequiredLog注解中的value
        //(1)获取目标方法的
        Method declaredMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
        //(2)获取目标方法的注解
        RequiredLog requiredLog = declaredMethod.getAnnotation(RequiredLog.class);
        //（3）获取注解的值
        String operation = "operation";
        if (requiredLog != null)
            operation = requiredLog.operation();
        //获取目标方法的参数
        String params = Arrays.toString(JP.getArgs());
        //2.封装用户行为
        SysLog entity = new SysLog();
        entity.setUsername("admin");
        entity.setOperation(operation);
        entity.setIp("0.0.0.0");
        entity.setMethod(method);
        entity.setParams(params);
        entity.setTime(time);
        entity.setCreatedTime(new Date());
        //3.保存用户行为，写入到数据库
        sysLogService.saveLog(entity);
    }
}
